package org.luxor.commons.core.web.controller;

import org.luxor.commons.core.config.properties.ExceptionProperties;
import org.luxor.commons.core.exception.BaseException;
import org.luxor.commons.core.utils.StringUtils;
import org.luxor.commons.core.web.RestStatus;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.client.HttpServerErrorException;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;


/**
 * Rest Controller基类
 *
 * @author XinmingYan @date 2019/9/16
 */
public abstract class BaseRestController extends BaseController {

    @Resource
    private ExceptionProperties exceptionProperties;

    @ExceptionHandler({BaseException.class})
    public BaseException processException(BaseException e) {
        return e;
    }

    @ExceptionHandler({Throwable.class})
    public BaseException processException(Throwable e) {
        return new BaseException(RestStatus.UNKNOWN, e);
    }

    @ExceptionHandler(AccessDeniedException.class)
    public BaseException handleAccessDeniedException(AccessDeniedException e) {
        return new BaseException(RestStatus.FORBIDDEN, StringUtils.toString(e));
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public BaseException handleDuplicateKeyException(DuplicateKeyException e) {
        return new BaseException(RestStatus.EXISTS_KEY, e);
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public BaseException doMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        List<String> msgList = new ArrayList<>();
        for (ObjectError objectError : e.getBindingResult().getAllErrors()) {
            msgList.add(objectError.getDefaultMessage());
        }
        String error = StringUtils.toString(msgList);
        return new BaseException(RestStatus.PARAM_ILLEGAL_FIELDS, error);
    }

    @ExceptionHandler({BindException.class})
    public BaseException doBindException(BindException e) {
        List<String> msgList = new ArrayList<>();
        for (ObjectError objectError : e.getBindingResult().getAllErrors()) {
            msgList.add(objectError.getDefaultMessage());
        }
        String error = StringUtils.toString(msgList);
        return new BaseException(RestStatus.PARAM_ILLEGAL_CONVERSION, error);
    }

    @ExceptionHandler(HttpServerErrorException.class)
    public BaseException doHttpServerErrorException(HttpServerErrorException e) {
        return new BaseException(RestStatus.SERVER_ERROR, e);
    }

    @ExceptionHandler({HttpMessageNotReadableException.class})
    public BaseException doHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        String msg = e.getMessage();
        if (msg != null && msg.startsWith("JSON parse error")) {
            String start = "field : ";
            String end = ";";
            msg = "字段[" + msg.substring(msg.indexOf(start) + start.length(), msg.indexOf(end)) + "]解析出错";
            return new BaseException(RestStatus.JSON_INVALID_PARSE, msg);
        }
        return new BaseException(RestStatus.UNKNOWN, e);
    }

    @ExceptionHandler({BadSqlGrammarException.class})
    public BaseException handleBadSqlGrammarException(Exception e) {
        if (exceptionProperties.isShowSqlDetail()) {
            return new BaseException(RestStatus.SQL_GRAMMAR, StringUtils.toString(e));
        }
        return new BaseException(RestStatus.SQL_GRAMMAR);
    }
}